package service

import (
	"bytes"
	"cgs-server/helper"
	"cgs-server/server/cgs/app/models"
	v1 "cgs-server/server/cgs/app/models/v1"
	"cgs-server/server/cgs/app/store"
	"cgs-server/server/model"
	"cgs-server/server/upload"
	"fmt"
	uuid "github.com/satori/go.uuid"
	"github.com/skip2/go-qrcode"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"strings"
	"time"
)

type PublicWorksheetSrv interface {
	Save(wg *models.PublicWorksheet, user *model.User) error
	Update(wg *models.PublicWorksheet, user *model.User) error
	Get(shareId string, user *model.User) (*models.PublicWorksheet, error)
	GetByWorksheetId(worksheetId string, user *model.User) (*models.PublicWorksheet, error)

	// SaveExtUrl 添加扩展地址
	SaveExtUrl(extUrl *models.ExtUrl, user *model.User) (*models.ExtUrl, error)
	DeleteExtUrl(id string, user *model.User) error

	// GenerateQRCode 生成二维码，返回地址
	GenerateQRCode(content string) (string, error)
}

type publicWorksheet struct {
	store store.Factory
}

func (w *publicWorksheet) GenerateQRCode(content string) (string, error) {
	encode, err := qrcode.Encode(content, qrcode.Medium, 256)
	if err != nil {
		return "", err
	}
	v4, err := uuid.NewV4()
	if err != nil {
		return "", err
	}
	uid := v4.String()
	uid = strings.ReplaceAll(uid, "-", "")
	fileStore := upload.NewFileStore(upload.MinIO)
	path := fmt.Sprintf("public/png/%s/%s%s", helper.TimeToString(time.Now(), "yyyyMMdd"), uid, ".png")
	s, err := fileStore.Upload(bytes.NewReader(encode), path, int64(len(encode)), "image/png")
	if err != nil {
		return "", err
	}
	return s, nil
}

func (w *publicWorksheet) SaveExtUrl(extUrl *models.ExtUrl, user *model.User) (*models.ExtUrl, error) {
	s, err := w.GenerateQRCode(extUrl.Url)
	if err != nil {
		return nil, err
	}
	extUrl.Qrcode = s

	err = w.store.PublicWorksheetExt().Save(extUrl, user, v1.CreateOptions{})
	if err != nil {
		return nil, err
	}
	return extUrl, nil
}

func (w *publicWorksheet) DeleteExtUrl(id string, user *model.User) error {
	hex, err := primitive.ObjectIDFromHex(id)
	if err != nil {
		return err
	}
	opt := v1.DeleteOptions{}
	opt.AddFilter("id", hex)
	err = w.store.PublicWorksheetExt().Delete(&models.ExtUrl{}, user, opt)
	return err
}

func (w *publicWorksheet) ListExtUrl(worksheetId string, user *model.User) (*models.ExtUrls, error) {
	opt := v1.ListOptions{}
	opt.AddFilter("worksheetId", worksheetId)
	list, err := w.store.PublicWorksheetExt().List(&models.ExtUrl{}, user, opt)
	if err != nil {
		return nil, err
	}
	return list, nil
}

func (w *publicWorksheet) GetByWorksheetId(worksheetId string, user *model.User) (*models.PublicWorksheet, error) {
	pw := &models.PublicWorksheet{}
	opt := v1.GetOptions{}
	opt.AddFilter("worksheetId", worksheetId)
	get, _ := w.store.PublicWorksheet().Get(pw, user, opt)
	if get == nil {
		pw.WorksheetId = worksheetId
		err := w.Save(pw, user)
		if err != nil {
			return nil, err
		}
	} else {
		pw = get
	}

	wsId, err := primitive.ObjectIDFromHex(pw.WorksheetId)
	if err != nil {
		return nil, err
	}

	info, err := w.store.WorksheetInfo().Get(&models.WorksheetInfo{Id: wsId}, user, v1.GetOptions{})
	if err != nil {
		return nil, err
	}

	wsInfo := models.WorksheetInfo{
		Id:      info.Id,
		Name:    info.Name,
		Fields:  info.Fields,
		AppId:   info.AppId,
		Config:  info.Config,
		GroupId: info.GroupId,
		Type:    info.Type,
		Icon:    info.Icon,
		Hidden:  &info.Hidden,
	}

	// 扩展参数
	url, err := w.ListExtUrl(worksheetId, user)
	if err != nil {
		return nil, err
	}
	if pw.ExtParam == nil {
		pw.ExtParam = &models.ExtParam{}
	}
	pw.ExtParam.ExtUrls = *url

	pw.WorksheetInfo = &wsInfo
	pw.ResolveCouldFill()

	return pw, nil
}

func (w *publicWorksheet) Get(shareId string, user *model.User) (*models.PublicWorksheet, error) {
	pw := &models.PublicWorksheet{}
	opt := v1.GetOptions{}
	opt.AddFilter("shareId", shareId)
	get, err := w.store.PublicWorksheet().Get(pw, user, opt)
	if err != nil {
		return nil, err
	}
	if get != nil {
		wsId, err := primitive.ObjectIDFromHex(get.WorksheetId)
		if err != nil {
			return nil, err
		}
		info, err := w.store.WorksheetInfo().Get(&models.WorksheetInfo{Id: wsId}, user, v1.GetOptions{})
		if err != nil {
			return nil, err
		}

		wsInfo := models.WorksheetInfo{
			Id:      info.Id,
			Name:    info.Name,
			Fields:  info.Fields,
			AppId:   info.AppId,
			Config:  info.Config,
			GroupId: info.GroupId,
			Type:    info.Type,
			Icon:    info.Icon,
			Hidden:  &info.Hidden,
		}

		get.WorksheetInfo = &wsInfo

		// 扩展参数
		url, err := w.ListExtUrl(get.WorksheetId, user)
		if err != nil {
			return nil, err
		}
		if get.ExtParam == nil {
			get.ExtParam = &models.ExtParam{}
		}
		get.ExtParam.ExtUrls = *url

		get.ResolveCouldFill()
	}

	return get, err
}

func (w *publicWorksheet) Update(wg *models.PublicWorksheet, user *model.User) error {
	// 二维码
	if wg.Url != "" {
		s, err := w.GenerateQRCode(wg.Url)
		if err != nil {
			return err
		}
		wg.Qrcode = s
	}
	updateOpt := v1.UpdateOptions{}
	updateOpt.AddFilter("worksheetId", wg.WorksheetId)
	err := w.store.PublicWorksheet().Update(wg, user, updateOpt)
	return err
}

func (w *publicWorksheet) Save(wg *models.PublicWorksheet, user *model.User) error {

	wg.FillTimes = new(int)
	wg.ExtParam = &models.ExtParam{}

	err := w.store.PublicWorksheet().Save(wg, user, v1.CreateOptions{})
	if err != nil {
		return err
	}

	return nil
}

func newPublicWorksheetSrv(s *service) PublicWorksheetSrv {
	return &publicWorksheet{
		store: s.store,
	}
}
